
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include <libwebsockets.h>
#include "sqlite3.h"
#include "database.h"
#ifndef SOFTWARE_NAME
#define SOFTWARE_NAME "wsdb"
#endif
#ifndef VERSION
#define VERSION "NO VERSION"
#endif
#define DB_NAME 	"dbchange/ts-3.1.2.db"
sqlite3 *db = NULL;
struct pss {
	struct lws_spa *spa;
};

static int interrupted, use303;

static const char * const param_names[] = {
	"query",
	"accountId",
	"token",
};

enum enum_param_names {
	EPN_QUERY,
	EPN_ACCOUNT_ID,
	EPN_TOKEN,
};

static int
callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
	      void *in, size_t len)
{
	struct pss *pss = (struct pss *)user;
	//uint8_t buf[LWS_PRE + LWS_RECOMMENDED_MIN_HEADER_SPACE], *start = &buf[LWS_PRE],
	uint8_t buf[LWS_PRE + 1024000], *start = &buf[LWS_PRE],
		*p = start, *end = &buf[sizeof(buf) - 1];
	size_t m, n;
  char *result = NULL;

	switch (reason) {
	case LWS_CALLBACK_HTTP:
		if (!strcmp((const char *)in, "/sql"))
			return 0;
		break;
	case LWS_CALLBACK_HTTP_BODY:
		if (!pss->spa) {
			pss->spa = lws_spa_create(wsi, param_names,
					LWS_ARRAY_SIZE(param_names), 1024,
					NULL, NULL); /* no file upload */
			if (!pss->spa)
				return -1;
		}
		if (lws_spa_process(pss->spa, in, (int)len))
			return -1;
		break;
	case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
		if (pss->spa && lws_spa_destroy(pss->spa))
			return -1;
		break;
	case LWS_CALLBACK_HTTP_BODY_COMPLETION:
		lwsl_user("LWS_CALLBACK_HTTP_BODY_COMPLETION\n");
		lws_spa_finalize(pss->spa);
		if (pss->spa)
			for (n = 0; n < (int)LWS_ARRAY_SIZE(param_names); n++) {
				if (!lws_spa_get_string(pss->spa, n))
					lwsl_user("%s: undefined\n", param_names[n]);
				else
					lwsl_user("%s: (len %d) '%s'\n",
					    param_names[n],
					    lws_spa_get_length(pss->spa, n),
					    lws_spa_get_string(pss->spa, n));
			}
    char *query = NULL;
    if (db) {
      query = strdup(lws_spa_get_string(pss->spa, 0));
    }
    if (pss->spa && lws_spa_destroy(pss->spa))
      return -1;
#define USE_USER
#ifdef USE_USER
    if (db) {
    //  const char *query = lws_spa_get_string(pss->spa, 0);
      result = database__sqlExecWithDbName(db, query, "wsdb");
      printf("[DEBUG] [%s]:%s\n", query, result);
      free(query);
      if (result)
        n = strlen(result);
      if (n > (sizeof(buf) - LWS_PRE)) {
        char tmp[1024];
        snprintf(tmp, sizeof(tmp), "too large :%ld buf size:%ld\n",
            n, sizeof(buf) - LWS_PRE);
        result = strdup(tmp);
        n = strlen(result);
      }
      if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK,
            "text/html", n, &p, end))
        return 1;
      if (lws_finalize_write_http_header(wsi, start, &p, end))
        return 1;
      if (result) {
        n = lws_snprintf((char *)p, sizeof(buf) - LWS_PRE, "%s",
            result);
        free(result);
      }
      m = lws_write(wsi, (uint8_t *)p, n, LWS_WRITE_HTTP_FINAL);
      if (m < n) {
        lwsl_err("ERROR %ld writing to socket\n", n);
        return -1;
      } else {
        //printf("[DEBUG] writed :%ld %s\n", m, p);
        printf("[----] http:%ld\n", m);
      }
      if (lws_http_transaction_completed(wsi))
        return -1;
      if (lws_http_transaction_completed(wsi))
        return -1;
    }
#endif
#ifndef USE_USER
		if (pss->spa && lws_spa_destroy(pss->spa))
			return -1;
		if (lws_http_redirect(wsi, use303 ? HTTP_STATUS_SEE_OTHER :
					   HTTP_STATUS_MOVED_PERMANENTLY,
				      (unsigned char *)"after-form1.html",
				      16, &p, end) < 0)
			return -1;
#endif
		break;
	case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
    if (!db) {
		if (pss->spa) {
			lws_spa_destroy(pss->spa);
			pss->spa = NULL;
		}
    }
		break;
	default:
		break;
	}
	return lws_callback_http_dummy(wsi, reason, user, in, len);
}

static struct lws_protocols protocols[] = {
	{ "http", callback_http, sizeof(struct pss), 0 },
	{ NULL, NULL, 0, 0 } /* terminator */
};
static const struct lws_http_mount mount = {
	/* .mount_next */	       NULL,		/* linked-list "next" */
	/* .mountpoint */		"/",		/* mountpoint URL */
#if defined(__x86_64__) || defined(_M_X64)
	/* .origin */		"./wsdb/mount-origin",	/* serve from dir */
#else
	/* .origin */		"./mount-origin",	/* serve from dir */
#endif
	/* .def */			"index.html",	/* default filename */
	/* .protocol */			NULL,
	/* .cgienv */			NULL,
	/* .extra_mimetypes */		NULL,
	/* .interpret */		NULL,
	/* .cgi_timeout */		0,
	/* .cache_max_age */		0,
	/* .auth_mask */		0,
	/* .cache_reusable */		0,
	/* .cache_revalidate */		0,
	/* .cache_intermediaries */	0,
	/* .origin_protocol */		LWSMPRO_FILE,	/* files in a dir */
	/* .mountpoint_len */		1,		/* char count */
	/* .basic_auth_login_file */	NULL,
};
void sigint_handler(int sig)
{
	interrupted = 1;
}
int main(int argc, const char **argv)
{
	struct lws_context_creation_info info;
	struct lws_context *context;
	const char *p;
	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
			/* for LLL_ verbosity above NOTICE to be built into lws,
			 * lws must have been configured and built with
			 * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
			/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
			/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
			/* | LLL_DEBUG */;
  int port = 7681, rc;
  const char *dbName = "./wsdb/wsdb.db";

	signal(SIGINT, sigint_handler);

	if ((p = lws_cmdline_option(argc, argv, "-d")))
		logs = atoi(p);
	if ((p = lws_cmdline_option(argc, argv, "-p")))
		port = atoi(p);
	if ((p = lws_cmdline_option(argc, argv, "-db")))
		dbName = p;

  rc = sqlite3_open(dbName, &db);
  if (rc != SQLITE_OK) {
    printf("[ERROR] can't open :%s\n", dbName);
    exit(1);
  }
	lws_set_log_level(logs, NULL);
	lwsl_user(
      "LWS minimal http server POST | visit http://localhost:%d\n",
      port);

	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
	info.port = port;
	info.protocols = protocols;
	info.mounts = &mount;
	info.options =
		LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;

	if (lws_cmdline_option(argc, argv, "-s")) {
		info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
		info.ssl_cert_filepath = "localhost-100y.cert";
		info.ssl_private_key_filepath = "localhost-100y.key";
	}

	if (lws_cmdline_option(argc, argv, "--303")) {
		lwsl_user("%s: using 303 redirect\n", __func__);
		use303 = 1;
	}

	context = lws_create_context(&info);
	if (!context) {
		lwsl_err("lws init failed\n");
		return 1;
	}

	while (n >= 0 && !interrupted)
		n = lws_service(context, 0);
  if (0) {
    char cmd[1024];
    snprintf(cmd, sizeof(cmd), "chromium 0.0.0.0:%d", port);
    system(cmd);
  }

	lws_context_destroy(context);

	return 0;
}

